#ifndef __COMMON__HEADER__
#define __COMMON__HEADER__

#include <string>
#include <iostream>

struct osip_mutex;
struct osip_sem;
struct osip_cond;
struct osip_thread;

struct eXosip_t;
struct eXosip_event;

#ifdef _CLOG_
// logger
#define BLANK       "SIP"
#define REGISTER    "REG"
#define INVITE      "IVT"
#define INFO        "INF"
#define MESSAGE     "MSG"
#define OPTIONS     "OPT"
#define Console(sub, args)                                                                  \
    do                                                                                      \
    {                                                                                       \
        Logger::Guard guard(sub);                                                                \
        guard.as_stream() args;                                                             \
    }while(false)


class LoggerData;
class Logger
{
public:
    static LoggerData* instance();
    class Guard
    {
    public:
        Guard(const std::string& sub);
        ~Guard();
        std::ostream& as_stream();
    };
private:
    static LoggerData* mImpl;
};
#endif

class ExosipAutoLock
{
public:
    ExosipAutoLock(eXosip_t* pCtx);
    ~ExosipAutoLock();
private:
    eXosip_t* mCtx;
};

// base class
namespace common
{
    class nocopyable {
    protected:
        nocopyable() {}
        ~nocopyable() {}
    private:
        nocopyable(const nocopyable&);
        const nocopyable& operator=(const nocopyable&);
    };

    //auto free only used for osip c-characters allocated by 'xxx_to_str()'
    class ostring {
    public:
        ostring();
        ~ostring();
        operator const char*() const { return osipcstr_; }
        const char* c_str() const { return osipcstr_; }
        operator char*() { return osipcstr_; }
        char** operator&() { return &osipcstr_; }
        const bool empty() const;
    private:
        char* osipcstr_;
    };

    class omutex : public nocopyable {
    public:
        omutex();
        ~omutex();
        bool lock();
        void unlock();
        osip_mutex* operator&() const { return mutex_; }
    private:
        osip_mutex* mutex_;
    };

    class oscope_lock : public nocopyable {
    public:
        oscope_lock(omutex& mut);
        ~oscope_lock();
        void unlock();
    private:
        omutex& mut_;
    };

    class osemaphore : public nocopyable {
    public:
        osemaphore(unsigned int count = 0);
        ~osemaphore();
        bool post();
        bool wait();
        bool trywait();
    private:
        osip_sem* sem_;
    };

    class ocondition : public nocopyable {
    public:
        ocondition();
        ~ocondition();
        bool signal();
        bool wait(omutex& mut, int tv_s = -1, int tv_ms = -1);
    private:
        osip_cond* cond_;
    };

    class othread : public nocopyable
    {
    public:
        othread();
        virtual ~othread();
        bool start();
        bool join();
        void stop();
        const bool is_running() const { return bRunning_; }
    protected:
        virtual bool startup() { return true; }
        virtual void dowork() = 0;
        virtual void cleanup() {};
    private:
        static void* _thread_entry_(void* param);
        void thread_proc();
        osip_thread* handle_;
        bool bRunning_;
    };

    class helper
    {
    public:
        class NetworkInitializer
        {
        public:
            NetworkInitializer();
            ~NetworkInitializer();
            operator bool() const;
        protected:
            bool mValid;
        };

        static void msleep(int millseconds);
        //return seconds
        static unsigned long long now_time();
        //return asctime without line break
        static const char* str_time(time_t t = 0);
        static std::string to_string(int val);
        template<class T, class R> static R convert(T t);
    };

} // namespace common

#endif // #ifndef #__COMMON__HEADER__

